﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Cache.CSRedis;
using EventBus.RabbitMQ;
using FluentValidation.AspNetCore;
using Grpc.Core;
using log4net.Repository.Hierarchy;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.OpenApi.Models;
using Order.CommandHandler;
using Order.Common;
using Order.Common.Command;
using Order.Common.IntegratedEvent;
using Order.Common.IocHelper;
using Order.Common.Logger;
using Order.Domain;
using Order.Domain.DomainService;
using Order.Domain.Repository;
using Order.EntityFrameworkCore;
using Order.EntityFrameworkCore.RepositoryImpl;
using OrderContext.Filter;
using WebApiClient;
using ILoggerFactory = Microsoft.Extensions.Logging.ILoggerFactory;
using WebApi.Swagger;
using OrderWebApi.Filter;
using Microsoft.AspNetCore.Http;
using System.Reflection;
using Common.Tools;

namespace OrderWebApi
{
    /// <summary>
    /// 依赖注入配置
    /// </summary>
    public class DependencyInjectionService
    {
        private static DependencyInjectionService _dependencyInjectionConfiguration;
        private static readonly object LockObj = new object();
        private static IServiceCollection _services;

        /// <summary>
        /// 单例模式
        /// </summary>
        /// <returns></returns>
        public static DependencyInjectionService GetInstance(IServiceCollection services)
        {
            _services = services;
            if (_dependencyInjectionConfiguration == null)
            {
                lock (LockObj)
                {
                    if (_dependencyInjectionConfiguration == null)
                    {
                        _dependencyInjectionConfiguration = new DependencyInjectionService();
                    }
                }
            }
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加AddDbContextPool
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddDbContextPool(IConfiguration configuration)
        {
            //注入配置文件
            _services.TryAddSingleton(new ConfigurationHelper(configuration));

            //EF日志
            ILoggerFactory efLoggerFactory
               = LoggerFactory.Create(builder =>
               {
                   builder
                       .AddFilter((category, level) =>
                           category == DbLoggerCategory.Database.Command.Name
                           && level == LogLevel.Information)
                       .AddConsole();
               });
            var databaseType = ConfigurationHelper.GetDatabaseType();
            //读取数据库连接字符串
            var connectionString = ConfigurationHelper.GetConnectionString();
            switch (databaseType)
            {
                case DatabaseType.SqlServer:
                    //使用DbContext连接池，poolSize不能超过100，
                    _services.AddDbContextPool<Order.EntityFrameworkCore.OrderContext>(
                        options => options.UseSqlServer(connectionString)//连接异常时重试次数
                                                                         //.AddInterceptors(new HintCommandInterceptor(_services))//ef 拦截器
                            .UseLoggerFactory(efLoggerFactory)//ef 日志记录
                            .UseLazyLoadingProxies(),
                        poolSize: 100);
                    break;
                case DatabaseType.Mysql:
                    //使用DbContext连接池，poolSize不能超过100，
                    _services.AddDbContextPool<Order.EntityFrameworkCore.OrderContext>(
                        options => options.UseMySql(connectionString, s => s.EnableRetryOnFailure(5))//连接异常时重试次数
                                                                                                     //.AddInterceptors(new HintCommandInterceptor(_services))//ef 拦截器
                            .UseLoggerFactory(efLoggerFactory)//ef 日志记录
                            .UseLazyLoadingProxies(),
                        poolSize: 100);
                    break;
                default:
                    break;
            }
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加MVC
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddMvc(Assembly[] assemblies)
        {
            _services.AddControllers(options =>
            {
                //options.Filters.Add(typeof(HttpActionFiler)); 

            }).AddJsonOptions(options =>
            {
                //忽略循环引用
                //options.JsonSerializerOptions.IgnoreReadOnlyProperties = true;
            }).AddFluentValidation(options =>
            {
                options.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
                var validatorList = GetFluentValidationValidator(assemblies);
                foreach (var item in validatorList)
                {
                    options.RegisterValidatorsFromAssemblyContaining(item);
                }
            });
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 获取所有的FluentValidation Validator的类
        /// </summary>
        public IEnumerable<Type> GetFluentValidationValidator(Assembly[] assemblies)
        {          
            if (!assemblies.Any())
            {
                throw new DllNotFoundException($"程序集不存在！");
            }
            var typs = RuntimeHelper.GetAllTypes(assemblies);
            var validatorList = typs.Where(e => e.Name.EndsWith("Validator"));
            return validatorList;
        }

        /// <summary>
        /// 添加Cookie
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddCookie()
        {
            //注册Cookie认证服务
            _services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加CAP
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddCap()
        {
            _services.AddCap(x =>
            {
                // 如果你的 SqlServer 使用的 EF 进行数据操作，你需要添加如下配置： 
                x.UseEntityFramework<Order.EntityFrameworkCore.OrderContext>();
                //x.UseSqlServer("Data Source=DESKTOP-G8UTIT6\\LI;Initial Catalog=Conference;User ID=sa;Password=123456li;MultipleActiveResultSets=true");
                //启用操作面板
                x.UseDashboard();

                // 如果你使用的 RabbitMQ 作为MQ，你需要添加如下配置：              
                x.UseRabbitMQ(cfg =>
                {
                    cfg.HostName = "47.104.83.210";
                    cfg.UserName = "lifeng";
                    cfg.Password = "lifeng123";
                });
                //设置失败重试次数
                x.FailedRetryCount = 50;
            });
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加跨域
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddCors()
        {
            //配置跨域处理
            _services.AddCors(options =>
            {
                options.AddPolicy("any", builder =>
                {
                    builder.AllowAnyOrigin() //允许任何来源的主机访问
                        .AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowCredentials();//指定处理cookie
                });
            });
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加Swagger
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddSwagger(IConfiguration configuration)
        {
            _services.AddExtensionSwagger(configuration);
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加DDD分层的注入
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddDddLayering(Assembly[] assemblies)
        {
            // 使用Mapper
            _services.AddAutoMapper(typeof(AutomapperConfig));
            //注入ExceptionLessLogger服务
            _services.AddSingleton<ILoggerHelper, ExceptionLessLogger>();
            //批量注入仓储Repository
            //_services.AddScoped<IOrderRepository, OrderRepository>();
            _services.RegisterAssembly(assemblies);
            //注入工作单元
            _services.AddScoped<IUnitOfWork, UnitOfWork>();
            //批量注入领域服务DomainService
            //_services.AddScoped(typeof(CreateOrderService));
            //_services.AddScoped(typeof(VerifySkuService));
            //_services.AddScoped(typeof(VerifyCustomerService));
            _services.RegisterDomainServiceAssembly(assemblies);          
            ////批量注入应用服务Service
            //_services.AddScoped<IOrderService, OrderService>();
            //_services.RegisterAssembly("Order.CommandHandler");

            //注入EventBus
            var options = new RabbitMQOptions { HostName = "127.0.0.1", UserName = "guest", Password = "guest" };
            _services.RabbitmqBus(options, assemblies, HandlerType.AllHandler);

            //注入CommandService
            _services.AddSingleton<ICommandService, CommandService>();
            _services.AddSingleton<IntegratedEventService, IintegratedEventService>();

            //注入IHttpContextAccessor，获取httpContext
            _services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加Redis
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddRedis()
        {
            RedisOptions options = new RedisOptions
            {
                HostName = "127.0.0.1",
                Port = 6379,
                Password = "abcdefg123456",
                DefaultDatabase = string.Empty,
                WriteBuffer = 10240,
                Prefix = string.Empty,
                TryIt = 3,
                PoolSize = 50,
                SSL = false,
                ExpireSeconds = 60,
                EnvName = string.Empty
            };
            _services.TryAddSingleton<IOptions<RedisOptions>>(options);
            _services.TryAddSingleton<IRedisHelper, CsRedisHelper>();
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加AddFluentValidationErrorMessage
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddFluentValidationErrorMessage()
        {
            _services.Configure<ApiBehaviorOptions>(options =>
            {
                options.InvalidModelStateResponseFactory = (context) =>
                {
                    var errors = context.ModelState
                        .Values
                        .SelectMany(x => x.Errors
                                    .Select(p => p.ErrorMessage))
                        .ToList();
                    var result = new ResponseResult<List<string>>
                    {
                        StatusCode = "00009",
                        Result = errors,
                        Message = string.Join(",", errors.Select(e => string.Format("{0}", e)).ToList()),
                        IsSucceed = false
                    };

                    return new BadRequestObjectResult(result);
                };
            });
            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加WebApiClient
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddWebApiClient<T>(string url) where T : class, IHttpApi
        {
            _services.AddSingleton<IHttpApiFactory<T>, HttpApiFactory<T>>(p =>
            {
                return new HttpApiFactory<T>().ConfigureHttpApiConfig(c =>
                {
                    c.HttpHost = new Uri(url);
                    c.LoggerFactory = p.GetRequiredService<ILoggerFactory>();
                    var IHttpContextAccessor = p.GetRequiredService<IHttpContextAccessor>();
                    c.GlobalFilters.Add(new WebApiClientGlobalFilter(IHttpContextAccessor));
                });
            });

            _services.AddTransient(p =>
            {
                var factory = p.GetRequiredService<IHttpApiFactory<T>>();
                return factory.CreateHttpApi();
            });

            return _dependencyInjectionConfiguration;
        }

        /// <summary>
        /// 添加GrpcClient
        /// </summary>
        /// <returns></returns>
        public DependencyInjectionService AddGrpcClient<TClient>(string url) where TClient : ClientBase
        {
            //Grpc忽略Https配置
            AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
            _services.AddGrpcClient<TClient>(o =>
            {
                o.Address = new Uri(url);
            });
            return _dependencyInjectionConfiguration;
        }

    }
}
